home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / util2 / fiflb381.lha / fifo-handler.c < prev    next >
C/C++ Source or Header  |  1995-12-19  |  33KB  |  1,311 lines

  1.  
  2. /*
  3.  *  FIFO-HANDLER.C    V38.1
  4.  *
  5.  *  Provide an interface to the fifo.library
  6.  *  Provide remote shell support, including "*", interactive and 2.0 support.
  7.  *
  8.  *  !!! MUST BE RUN, CANNOT USE MOUNT !!!
  9.  *
  10.  *  FIFO:fifo_name/flags
  11.  *           r    for reading
  12.  *           w    for writing
  13.  *           c    cooked (else raw)
  14.  *           e    EOF on close (if a writer)
  15.  *           k    allows writer to close before reader opens without
  16.  *            any data lost.
  17.  *           K    a reader MUST exist or write(s) will fail
  18.  *           q    QUIT (debugging)
  19.  *           m    master
  20.  *           t    tee off the read stream (no interference with other
  21.  *            readers)
  22.  *           s    shell
  23.  *
  24.  *           d    debug mode (read by running 'RemCLI DBFifo')
  25.  */
  26.  
  27. #define CLI_START
  28.  
  29. #include "handler.h"
  30.  
  31. /*  These packets are strictly internal to the handler */
  32. #define FACTION_SCREEN_MODE    ACTION_WRITE_RETURN
  33. #define FACTION_WAIT_CHAR    ACTION_READ_RETURN
  34. #define ACTION_WAIT_TIMEOUT    ACTION_TIMER
  35.  
  36. #define SIGS    (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)
  37.  
  38. #if !defined(__GNUC__)
  39. #define __inline__
  40. #endif
  41.  
  42. int myexit(int);
  43. void Initialize(void);
  44. void returnpacket(DosPacket *);
  45. void HandleRequestMsg(Message *);
  46. void WaitMsg(Message *);
  47. void SigHandles(char *, unsigned long);
  48. void xprintf(char *, ...);
  49. __inline__ static void *DosAllocMem(long);
  50. FHan *OpenHandle(char *, char *, long, long);
  51. void CloseHandle(FHan *);
  52. __inline__ static void DosFree(void *);
  53. MsgPort *SpecPort(FHan *);
  54. void MkDevice(char *);
  55. void DelDevice(void);
  56. WaitTreq *AllocTimerequest(unsigned long timeout);
  57. __inline__ static char not_console(char *, unsigned char);
  58.  
  59. MsgPort        *IoSink;
  60. MsgPort        *PktPort, *TimerPort;
  61. long        PortsMask;        /*  could be local ... */
  62. #ifndef CLI_START
  63. DeviceNode  *DevNode;
  64. #endif
  65. struct Library  * FifoBase;
  66. WaitTreq    *TimerIO;
  67. List        HanList;
  68. #ifdef DEBUG
  69. FifoHan        DBFifo;
  70. short        DDebug;
  71. #define D(x)  if (DDebug) x ;
  72. #define ebug  xprintf
  73. #else
  74. #define D(x)  ;
  75. #endif
  76. short        Done;    /*  could be local, but DICE2.06 uses up a register */
  77.  
  78. extern struct ExecBase * SysBase;
  79. extern struct DosLibrary * DOSBase;
  80.  
  81. const char verstring[] = "\0$VER: fifo-handler 38.1 (20.12.95)\r\n";
  82.  
  83.  
  84. __inline__ static char
  85. not_console(char *bas, unsigned char len)
  86. {
  87.     short n = 7;
  88.     if (*bas == '*')
  89.     return *(bas+1);
  90.     if (len <= (unsigned char) n)
  91.     return n;
  92.     {
  93.     const char *console = "CONSOLE:";
  94.     char r1, r2;
  95.  
  96.     while(!(r1=*console++ - (char)((r2=*bas++) >= 'a' ? r2 - ('a' - 'A') : r2))
  97.           /* && r2 */ && --n != -1) ;
  98.     return r1;
  99.     }
  100. }
  101.  
  102. #if !defined(__GNUC__)
  103. __stkargs int            /*  changed from void (jch) */
  104. _main(char *arg, long len)
  105. #else
  106. int _main(void)            /*  my special startup since libnix is >=2.0 */
  107. #endif
  108. {
  109.     DosPacket  *packet;
  110.  
  111.     NewList((MaxList *)&HanList);
  112.  
  113.     Initialize();
  114.     if (FifoBase == NULL)
  115.     return myexit(RETURN_FAIL);
  116.  
  117.     /*
  118.      *    Main Loop
  119.      */
  120.  
  121.     while (!Done || HanList.mlh_TailPred != (Node *)&HanList) {
  122.     {
  123.         Message *msg;
  124.  
  125.         while ((msg = GetMsg(IoSink)))
  126.         HandleRequestMsg(msg);
  127.         if ((msg = GetMsg(PktPort)) == NULL) {
  128.         /*  handler depends on TimerPort being used last */
  129.         if ((msg = GetMsg(TimerPort)) == NULL) {
  130.             if (Wait(SIGS | PortsMask) & SIGBREAKF_CTRL_C)
  131.             Done = 1;
  132.             continue;
  133.         } else {
  134.             /*  Got a timeout from timer.device */
  135.             packet = ((WaitTreq *)msg)->wt_packet;
  136.             ((WaitTreq *)msg)->wt_packet = NULL; /*  means timeout */
  137.         }
  138.         } else
  139.         packet = (DosPacket *)msg->mn_Node.ln_Name;
  140.     }
  141.     switch(packet->dp_Type) {
  142.     case ACTION_WRITE:
  143.     case FACTION_SCREEN_MODE:
  144.     case FACTION_WAIT_CHAR:
  145.     case ACTION_WAIT_TIMEOUT:
  146.         break;        /*  use dp_Res1 for temporary storage */
  147.     default:
  148.         packet->dp_Res1 = DOS_TRUE;
  149.     }
  150.     packet->dp_Res2 = DOS_FALSE;
  151.  
  152.     D(ebug("packet %ld\n", packet->dp_Type));
  153.  
  154.     switch(packet->dp_Type) {
  155.     case ACTION_DIE:
  156.         Done = 1;
  157.         break;
  158.     case ACTION_FINDUPDATE:        /*    FileHandle,Lock,Name        Bool    */
  159.     case ACTION_FINDINPUT:        /*    FileHandle,Lock,Name        Bool    */
  160.     case ACTION_FINDOUTPUT:        /*    FileHandle,Lock,Name        Bool    */
  161.         {
  162.         FileHandle *fh = BTOC(packet->dp_Arg1);
  163.         char fifo_name_m[128];
  164.         char fifo_name_s[128];
  165.         long han_flags = 0;
  166.         long opn_flags = FIFOF_NORMAL | FIFOF_NBIO;
  167.         short error = 0;
  168.  
  169.         {
  170.             char *bas = BTOC(packet->dp_Arg3);
  171.             char *ptr;
  172.             unsigned char len = *(unsigned char *)bas++;
  173.  
  174.             D(ebug("open: %*.*s\n", len, len, bas));
  175.  
  176.             if (!not_console(bas, len)) { /*  either "*" or "Console:" */
  177.             if (fh->fh_Port && (long)fh->fh_Port != -1) {
  178.                 FHan *han;
  179.                 /*  assume IntCode() filled fh_Port with port */
  180.                 /*  ln_name was filled with FHan by SpecPort() */
  181.                 han = (FHan *)fh->fh_Port->mp_Node.ln_Name;
  182.                 ++han->ff_Refs;
  183.                 fh->fh_Arg1 = (LONG)han;
  184.                 fh->fh_Port = (MsgPort *)DOS_TRUE; /*  means interactive */
  185.                 break;
  186.             }
  187.             /* fh->fh_Port = (MsgPort *)DOS_FALSE; */
  188.             packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  189.             break;
  190.             }
  191.  
  192.             /*  skip "fifo:" part */
  193.             for (ptr = bas; len && *ptr != ':'; ++ptr, --len) ;
  194.             if (len && *ptr == ':') {
  195.             bas = ptr + 1;
  196.             --len;
  197.             } else {
  198.             len = ptr - bas;
  199.             }
  200.             for (ptr = bas; *ptr != '/' && len; ++ptr, --len) ;
  201.             {
  202.             short i = ptr - bas;
  203.             if (/* i && */ i < 126) {
  204.                 strncpy(fifo_name_m, bas, i);
  205.                 strncpy(fifo_name_s, bas, i);
  206.                 /*  GCC can optimize these into MOVEB sequences */
  207.                 strcpy(fifo_name_m + i, "_m");
  208.                 strcpy(fifo_name_s + i, "_s");
  209.             } else
  210.                 error = 1; /*  nevertheless get flags */
  211.             }
  212.             /*  get flags */
  213.             if (len && *ptr == '/') {
  214.             unsigned long sigs = 0;
  215.             for (++ptr, --len; len; ++ptr, --len) {
  216.                 switch(*ptr) {
  217.                 case 'q':
  218.                 Done = 1;
  219.                 break;
  220.                 case 'e':
  221.                 han_flags |= FHF_CLOSEEOF;
  222.                 break;
  223.                 case 'c':
  224.                 han_flags |= FHF_COOKED;
  225.                 break;
  226.                 case 's':
  227.                 han_flags |= FHF_SHELL;
  228.                 break;
  229.                 case 'r':
  230.                 han_flags |= FHF_READ;
  231.                 break;
  232.                 case 'w':
  233.                 han_flags |= FHF_WRITE;
  234.                 break;
  235.                 case 'k':
  236.                 opn_flags |= FIFOF_KEEPIFD;
  237.                 break;
  238.                 case 'K':
  239.                 opn_flags |= FIFOF_RREQUIRED;
  240.                 break;
  241.                 case 'm':
  242.                 han_flags |= FHF_MASTER;
  243.                 break;
  244.                 case 't':
  245.                 han_flags |= FHF_TEE;
  246.                 break;
  247.                 case 'd':
  248. #ifdef DEBUG
  249.                 if (DDebug == 0) {
  250.                     DDebug = 1;
  251.                     DBFifo = OpenFifo("DBFifo_s", 1024, FIFOF_WRITE | FIFOF_NORMAL);
  252.                 }
  253. #endif
  254.                 break;
  255.                 case 'x':
  256. #ifdef DEBUG
  257.                 if (DDebug) {
  258.                     DDebug = 0;
  259.                     if (DBFifo)
  260.                     CloseFifo(DBFifo, FIFOF_EOF);
  261.                     DBFifo = NULL;
  262.                 }
  263. #endif
  264.                 break;
  265.                 case 'C':
  266.                 sigs |= SIGBREAKF_CTRL_C;
  267.                 break;
  268.                 case 'D':
  269.                 sigs |= SIGBREAKF_CTRL_D;
  270.                 break;
  271.                 case 'E':
  272.                 sigs |= SIGBREAKF_CTRL_E;
  273.                 break;
  274.                 case 'F':
  275.                 sigs |= SIGBREAKF_CTRL_F;
  276.                 break;
  277.                 default:
  278.                 error = 1;
  279.                 break;
  280.                 }
  281.             }
  282.             if (sigs)
  283.                 SigHandles((han_flags & FHF_MASTER)
  284.                        ? fifo_name_m : fifo_name_s, sigs);
  285.             }
  286.         }
  287.         if (((han_flags & FHF_COOKED) &&
  288.              ((han_flags & FHF_MASTER) || /*  as documented */
  289.               !(han_flags & FHF_READ)))     /*  necessary     */
  290.             || !(han_flags & (FHF_READ | FHF_WRITE)))
  291.             error = 1;
  292.         /*
  293.          *  To handle the stderr channel, "*", an interactive
  294.          *  shell must be opened with the 's' flag, which causes
  295.          *  a special message port to be created for the interactive
  296.          *  shell (and thus the pr_ConsoleTask field)
  297.          *
  298.          *  To handle COOKED data mode, FIFO: itself must processed
  299.          *  received data before the slave device, echoing it back
  300.          *  on the master channel and doing other cooked processing.
  301.          */
  302.  
  303.         if (!error) {
  304.             FHan *han;
  305.             if (NULL != (han = OpenHandle(fifo_name_s, fifo_name_m, han_flags, opn_flags))) {
  306.             if (han_flags & FHF_SHELL) {
  307.                 fh->fh_Type = han->ff_Port;    /*  special port */
  308.             }
  309.             fh->fh_Arg1 = (LONG)han;
  310.             fh->fh_Port = (MsgPort *)DOS_TRUE; /*  means interactive */
  311.             han->ff_SigPort = packet->dp_Port; /*  for SIGBREAKF_CTRL_* */
  312.             break;
  313.             } else {
  314.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  315.             break;
  316.             }
  317.         }
  318.         packet->dp_Res2 = ERROR_BAD_STREAM_NAME;
  319.         }
  320.         break;
  321.     case ACTION_READ:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  322.         /*
  323.          *    read from fifo.     If we are in cooked mode this action is
  324.          *    only able to read from the cooked buffer, and then only
  325.          *    if a line is complete.
  326.          */
  327.  
  328.         {
  329.         FHan *han = (FHan *)packet->dp_Arg1;
  330.         long n;
  331.  
  332.         if (!(han->ff_Flags & FHF_READ)) {
  333.             packet->dp_Res1 = -1;
  334.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  335.             returnpacket(packet); /*  or loose dp_Res1 */
  336.             packet = NULL;
  337.             break;
  338.         }
  339.         if (han->ff_Flags & FHF_REOF) {
  340.             han->ff_Flags &= ~FHF_REOF;
  341.             packet->dp_Res1 = 0;
  342.             break;
  343.         }
  344.         if (han->ff_Flags & FHF_COOKED) {
  345.             if ((n = strlen(han->ff_CookBuf)) != han->ff_CookIdx || han->ff_LRet) {
  346.             ++n;
  347.             if (n > packet->dp_Arg3)
  348.                 n = packet->dp_Arg3;
  349.             else
  350.                 han->ff_CookBuf[n-1] = '\n';
  351.             memmove((void *)packet->dp_Arg2, han->ff_CookBuf, n);
  352.             han->ff_CookIdx -= n;
  353.             /*  overlapping memory! */
  354.             memmove(han->ff_CookBuf, han->ff_CookBuf + n, han->ff_CookIdx + 1);
  355.             if (han->ff_CookIdx == 0)
  356.                 han->ff_LRet = 0;
  357.             packet->dp_Res1 = n;
  358.  
  359.             /*
  360.              *  if we blocked on reading the fifo to cook more
  361.              *  data, we unblock it here.
  362.              */
  363.  
  364.             han->ff_Flags &= ~FHF_COOKBFUL;
  365.  
  366.             if ((han->ff_Flags & FHF_RPEND) == 0) {
  367.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  368.                 han->ff_Flags |= FHF_RPEND;
  369.             }
  370.             break;
  371.             }
  372.         } else {    /*  not cooked */
  373.             char *ptr;
  374.             n = ReadFifo(han->ff_FifoR, &ptr, 0);
  375.             if (n < 0 /* || (n == 0 && (han->ff_Flags & FHF_REOF)--impossible)*/) {
  376.             han->ff_Flags &= ~FHF_REOF;
  377.             packet->dp_Res1 = 0;
  378.             break;
  379.             }
  380.             if (n > 0) {
  381.             /* Hans Verkuil introduced a patch to only read upto \n,
  382.              * however RAW: does not exhibit this behaviour.
  383.              */
  384.             if (n > packet->dp_Arg3)
  385.                 n = packet->dp_Arg3;
  386.             CopyMem(ptr, (void *)packet->dp_Arg2, n);
  387.             if (ReadFifo(han->ff_FifoR, &ptr, n) < 0)
  388.                 han->ff_Flags |= FHF_REOF;
  389.             /*
  390.              *  Concatenating data when last result is > 0 gives
  391.              *  not much, as with the way packets are sequenced
  392.              *  here, it is usually only possible once when
  393.              *  unblocking from a full buffer.
  394.              */
  395.             packet->dp_Res1 = n;
  396.             break;
  397.             }
  398.         }
  399.  
  400.         /*
  401.          *  blocked
  402.          */
  403.  
  404.         AddTail((MaxList *)&han->ff_RdWait, &packet->dp_Link->mn_Node);
  405.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  406.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  407.             han->ff_Flags |= FHF_RPEND;
  408.         }
  409.         packet = NULL;
  410.         }
  411.         break;
  412.     case ACTION_WRITE:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  413.         {
  414.         FHan *han = (FHan *)packet->dp_Arg1;
  415.         long n;
  416.         long i;
  417.  
  418.         if (!(han->ff_Flags & FHF_WRITE)) {
  419.             packet->dp_Res1 = -1;
  420.             packet->dp_Res2 = ERROR_WRITE_PROTECTED;
  421.             returnpacket(packet); /*  or loose dp_Res1 */
  422.             packet = NULL;
  423.             break;
  424.         }
  425.  
  426.         i = packet->dp_Arg3;
  427.         if (i < 0) {    /*  re-scan    */
  428.             i = -i;
  429.             packet->dp_Arg3 = i;
  430.         } else {    /*  initial pkt */
  431.             packet->dp_Res1 = 0;
  432.         }
  433.  
  434.  
  435.         /*
  436.          *  check for output stopped due to pending input line
  437.          *
  438.          *  dp_Arg3 < 0 indicates a re-scan (so we do not clear
  439.          *  our dp_Res1 field that is tracking the amnt written)
  440.          */
  441.  
  442.         if ((han->ff_Flags & FHF_COOKED) && han->ff_CookIdx && han->ff_LRet == 0) {
  443.             packet->dp_Arg3 = -packet->dp_Arg3;
  444.             AddTail((MaxList *)&han->ff_WrWait, &packet->dp_Link->mn_Node);
  445.             han->ff_Flags |= FHF_WIHOLD;
  446.             packet = NULL;
  447.             break;
  448.         }
  449.  
  450.  
  451.         /*
  452.          *  limit size of writes to fifo to something the fifo can
  453.          *  handle.  If cooked mode writer, prepend CR to LF's.
  454.          */
  455.  
  456.         if (i > han->ff_FHBufSiz)
  457.             i = han->ff_FHBufSiz;
  458.  
  459.         if (han->ff_Flags & FHF_COOKED) {
  460.             char *ptr = (char *)packet->dp_Arg2;
  461.             long j;
  462.  
  463.             /*  n is always initialized because i >= 0 */
  464.             for (j = 0; j < i; ++j) {
  465.             if (ptr[j] == '\n') {
  466.                 if (j == 0) {
  467.                 n = WriteFifo(han->ff_FifoW, "\r\n", 2);
  468.                 if (n == 2)
  469.                     n = 1;    /*  skip LF */
  470.                 break;
  471.                 }
  472.                 n = WriteFifo(han->ff_FifoW, ptr, j);
  473.                 break;
  474.             }
  475.             }
  476.             if (i == j)
  477.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  478.         } else
  479.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  480.  
  481.         /*
  482.          *  object too large or broken pipe
  483.          */
  484.  
  485.         if (n < 0) {    /*  most probably for FIFO_RREQUIRED */
  486.             packet->dp_Res1 = -1;
  487.             packet->dp_Res2 = (n == -2)
  488.               ? ERROR_OBJECT_TOO_LARGE /*  can this really happen? */
  489.               : ERROR_WRITE_PROTECTED;
  490.             returnpacket(packet); /*  or loose dp_Res1 */
  491.             packet = NULL;
  492.             break;
  493.         }
  494.  
  495.         packet->dp_Res1 += n;
  496.         if (n == packet->dp_Arg3)
  497.             break;
  498.  
  499.         packet->dp_Arg3 = -(packet->dp_Arg3 - n);
  500.         packet->dp_Arg2 += n;
  501.  
  502.         /*
  503.          *  blocked (n == 0)
  504.          *  or splitted
  505.          */
  506.  
  507.         AddTail((MaxList *)&han->ff_WrWait, &packet->dp_Link->mn_Node);
  508.         if ((han->ff_Flags & FHF_WAVAIL) == 0) {
  509.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  510.             han->ff_Flags |= FHF_WAVAIL;
  511.         }
  512.         packet = NULL;
  513.         }
  514.         break;
  515.     case ACTION_REQUEST:        /*    FHArg1, msg, how        Bool    */
  516.         {
  517.         FHan *han = (FHan *)packet->dp_Arg1;
  518.  
  519.         if ((unsigned short)packet->dp_Arg3 == FREQ_RPEND) {
  520.             if (han->ff_FifoR) {
  521.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  522.             break;
  523.             }
  524.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_WAVAIL) {
  525.             if (han->ff_FifoW) {
  526.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  527.             break;
  528.             }
  529.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_ABORT) {
  530.             if (han->ff_FifoR)
  531.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  532.             if (han->ff_FifoW)
  533.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  534.             break;
  535.         }
  536.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  537.         }
  538.         break;
  539.     case ACTION_END:        /*    FHArg1                Bool:TRUE    */
  540.         {
  541.         FHan *han = (FHan *)packet->dp_Arg1;
  542.  
  543.         if (--han->ff_Refs == 0) {
  544.             if (han->ff_Flags & FHF_RPEND) {
  545.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  546.             WaitMsg(&han->ff_RdMsg);
  547.             }
  548.             if (han->ff_Flags & FHF_WAVAIL) {
  549.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_ABORT);
  550.             WaitMsg(&han->ff_WrMsg);
  551.             }
  552.             /*  no need to do bookkeeping for ACTION_WAIT_CHAR */
  553.             returnpacket(packet);   /*  before ff_Port goes away */
  554.             packet = NULL;
  555.             CloseHandle(han);
  556.         }
  557.         }
  558.         break;
  559.     /*  Added for 37.5 and 38.0 */
  560.     case FACTION_WAIT_CHAR:        /*    timeout                Bool    */
  561.         /*
  562.          *  as ACTION_WAIT_CHAR does not give a filehandle, we get it
  563.          *  indirectly through the special port. Fold packet type for safety.
  564.          */
  565.         packet->dp_Type = ACTION_WAIT_CHAR;
  566.         {
  567.         FHan *han = (FHan *) (((MsgPort *) packet->dp_Res1)->mp_Node.ln_Name);
  568.         unsigned long timeout = packet->dp_Arg1;
  569.         WaitTreq *treq;
  570.  
  571.         if (!(han->ff_Flags & FHF_READ)) {
  572.             packet->dp_Res2 = ERROR_READ_PROTECTED;
  573.             break;
  574.         }
  575.         if (han->ff_Flags & FHF_REOF) {
  576.             packet->dp_Res1 = DOS_TRUE;
  577.             break;
  578.         }
  579.         if (han->ff_Flags & FHF_COOKED) {
  580.             if (han->ff_LRet || strlen(han->ff_CookBuf) != han->ff_CookIdx) {
  581.             packet->dp_Res1 = DOS_TRUE;
  582.             break;
  583.             }
  584.         } else {
  585.             char *ptr;
  586.             if (ReadFifo(han->ff_FifoR, &ptr, 0)) {
  587.             /*  result either -1 (EOF) or something is available */ 
  588.             packet->dp_Res1 = DOS_TRUE;
  589.             break;
  590.             }
  591.         }
  592.         if (timeout <= 50 /* microseconds */) {
  593.             packet->dp_Res1 = DOS_FALSE;
  594.             break;
  595.         }
  596.  
  597.         /*
  598.          *  queue packet
  599.          */
  600.  
  601.         if (NULL != (treq = AllocTimerequest(timeout))) {
  602.             treq->wt_packet = packet;
  603.             packet->dp_Type = ACTION_WAIT_TIMEOUT;
  604.             packet->dp_Res1 = (LONG)treq;
  605.             AddTail((MaxList *)&han->ff_RdWait, &packet->dp_Link->mn_Node);
  606.             if (!(han->ff_Flags & FHF_RPEND)) {
  607.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  608.             han->ff_Flags |= FHF_RPEND;
  609.             }
  610.             SendIO(&treq->wt_timereq.tr_node);
  611.             packet = NULL;
  612.             break;
  613.         } else
  614.             packet->dp_Res2 = ERROR_NO_FREE_STORE;
  615.         }
  616.         break;
  617.     case ACTION_WAIT_TIMEOUT:
  618.         packet->dp_Type = ACTION_WAIT_CHAR;
  619.         if (((WaitTreq *)packet->dp_Res1)->wt_packet) {
  620.             /*  input is available */
  621.         struct IORequest *ior = (struct IORequest *)packet->dp_Res1;
  622.  
  623.         if (!CheckIO(ior))
  624.             AbortIO(ior);
  625.         WaitIO(ior);
  626.         FreeMem((void *)ior, sizeof(WaitTreq));
  627.         packet->dp_Res1 = DOS_TRUE;
  628.         } else {
  629.         /*  timer.device timeout */
  630.  
  631.         /*
  632.          *  we know that node is still in han->ff_RdWait
  633.          *  because TimerPort is checked last
  634.          */
  635.         Remove(&packet->dp_Link->mn_Node);
  636.         /*  no need to try to abort the read request */
  637.         FreeMem((void *)packet->dp_Res1, sizeof(WaitTreq));
  638.         packet->dp_Res1 = DOS_FALSE;
  639.         }
  640.         break;
  641.     case FACTION_SCREEN_MODE:   /*    Mode                Bool:TRUE */
  642.         /* As ACTION_SCREEN_MODE does not give a filehandle, we get it
  643.          * indirectly through the special port. Fold packet type for safety.
  644.          */
  645.         packet->dp_Type = ACTION_SCREEN_MODE;
  646.         D(ebug("SCREEN_MODE %ld\n", packet->dp_Arg1));
  647.         {
  648.         /*  special port passed in dp->Res1 */
  649.         FHan *han = (FHan *)(((MsgPort *)packet->dp_Res1)->mp_Node.ln_Name);
  650.  
  651.         if (han->ff_CookBuf == NULL) {
  652.             /* Normally     a shell uses cooked mode and programs might
  653.              * also set cooked mode at exit. Thus if the
  654.              * application did not open FIFO: in cooked mode, it
  655.              * had good reasons to do so and we refuse any change.
  656.              * At least this is good for GNUEmacs (uses "rwesK").
  657.              */
  658.             packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
  659.             break;
  660.         }
  661.  
  662.         switch (packet->dp_Arg1) {
  663.         /*  another possibility would be if DOS_FALSE COOKED else RAW */
  664.         case DOS_TRUE:    /*    RAW    */
  665.         case 1:        /*  special case for bad programs, ls-4.7ljr */
  666.             if (han->ff_Flags & FHF_COOKED) {
  667.             han->ff_Flags &= ~(FHF_COOKED|FHF_WIHOLD|FHF_COOKECHOBLK|FHF_COOKBFUL);
  668.  
  669.             /*  unblock readers probably in FHF_COOKECHOBLK */
  670.             if ((han->ff_Flags & FHF_READ) && !(han->ff_Flags & FHF_RPEND)) {
  671.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  672.                 han->ff_Flags |= FHF_RPEND;
  673.             }
  674.             /*  unblock writers probably in FHF_WIHOLD */
  675.             if ((han->ff_Flags & FHF_WRITE) && !(han->ff_Flags & FHF_WAVAIL)) {
  676.                 RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  677.                 han->ff_Flags |= FHF_WAVAIL;
  678.             }
  679.             }
  680.             break;
  681.         case DOS_FALSE:    /*    COOKED    */
  682.             if (!(han->ff_Flags & FHF_COOKED)) {
  683.             /*  but ff->CookBuf is NULL if not opened with 'c' flag! */
  684.             han->ff_Flags |= FHF_COOKED;
  685.             /*  cooked processing depends on a read request being active */
  686.             if ((han->ff_Flags & FHF_READ) && !(han->ff_Flags & FHF_RPEND)) {
  687.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  688.                 han->ff_Flags |= FHF_RPEND;
  689.             }
  690.             }
  691.             break;
  692.         default:
  693.             packet->dp_Res2 = ERROR_BAD_NUMBER;
  694.         }
  695.         }
  696.         break;
  697.     /*  Added for 38.1 */
  698.     case ACTION_CHANGE_SIGNAL:    /*  Filehandle,port|NULL    Bool,port */
  699.         {
  700.         FHan *han = (FHan *)packet->dp_Arg1;
  701.         packet->dp_Res2 = (LONG)han->ff_SigPort;
  702.         D(ebug("Signal Port change %08lx\n", packet->dp_Arg2));
  703.         if (packet->dp_Arg2)
  704.             han->ff_SigPort = (MsgPort *)packet->dp_Arg2;
  705.         returnpacket(packet);    /*  or loose dp_Res1 */
  706.         packet = NULL;
  707.         }
  708.         break;
  709.     /*  Added for 38.1 */
  710.     case ACTION_IS_FILESYSTEM:  /*                    Bool */
  711.         packet->dp_Res1 = DOS_FALSE;
  712.         break;
  713.     /*  Added for 38.1 */
  714.     case ACTION_SEEK:        /*    FHArg1,Position,Mode        OldPosition */
  715.         packet->dp_Res1 = -1;   /*  do not return 0 */
  716.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  717.         returnpacket(packet);    /*  or loose dp_Res1 */
  718.         packet = NULL;
  719.         break;
  720.     default:
  721.         D(ebug("UNKNOWN packet\nArg1 %08lx Arg2 %08lx\n",
  722.            packet->dp_Arg1, packet->dp_Arg2));
  723.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  724.         break;
  725.     }
  726.     if (packet) {
  727.         if (packet->dp_Res2)
  728.         packet->dp_Res1 = DOS_FALSE;
  729.         returnpacket(packet);
  730.     }
  731.     }
  732.     return myexit(RETURN_OK);
  733. }
  734.  
  735. FHan *
  736. OpenHandle(r_name, w_name, han_flags, opn_flags)
  737. char *r_name;    /*  slave name    */
  738. char *w_name;    /*  master name */
  739. long han_flags;
  740. long opn_flags;
  741. {
  742.     FHan *han;
  743.  
  744.     if (NULL == (han = (FHan *)AllocMem(sizeof(FHan) + strlen(r_name) +1,
  745.                     MEMF_CLEAR | MEMF_PUBLIC)))
  746.     return NULL;
  747.     if (!(han_flags & FHF_MASTER)) {
  748.     char *swap = r_name;
  749.     r_name = w_name;
  750.     w_name = swap;
  751.     }
  752.     han->ff_Node.ln_Name = (char *)(han + 1);
  753.     strcpy(han->ff_Node.ln_Name, w_name);
  754.  
  755.     if ((han_flags & FHF_TEE) == 0 && (han_flags & FHF_READ)) {
  756.     FHan *h2;
  757.     for (h2 = (FHan *)HanList.mlh_Head; h2->ff_Node.ln_Succ; h2 = (FHan *)h2->ff_Node.ln_Succ) {
  758.         if (strcmp(h2->ff_Node.ln_Name, han->ff_Node.ln_Name) == 0) {
  759.         if ((h2->ff_Flags & FHF_TEE) == 0 && h2->ff_SRead) {
  760.             han->ff_SRead = h2->ff_SRead;
  761.             ++han->ff_SRead->sr_Refs;
  762.             break;
  763.         }
  764.         }
  765.     }
  766.     }
  767.     AddTail((MaxList *)&HanList, &han->ff_Node);
  768.  
  769.     if ((han_flags & FHF_READ) && han->ff_SRead == NULL) {
  770.     if (NULL == (han->ff_SRead = AllocMem(sizeof(SharRead), MEMF_CLEAR | MEMF_PUBLIC)))
  771.         goto fail;
  772.     han->ff_SRead->sr_Refs    = 1;
  773.     if (NULL == (han->ff_SRead->sr_FifoR = OpenFifo(r_name, FIFO_SIZE, opn_flags | FIFOF_READ)))
  774.         goto fail;
  775.     }
  776.     if (han_flags & FHF_WRITE) {
  777.     if (NULL == (han->ff_FifoW = OpenFifo(w_name, FIFO_SIZE, opn_flags | FIFOF_WRITE)))
  778.         goto fail;
  779.     han->ff_FHBufSiz = (BufSizeFifo(han->ff_FifoW) >> 1) -1;
  780.     }
  781.     if (han_flags & FHF_SHELL) {
  782.     if (NULL == (han->ff_Port = SpecPort(han)))
  783.         goto fail;
  784.     }
  785.  
  786.     han->ff_Flags = han_flags;
  787.     han->ff_Refs = 1;
  788.     han->ff_RdMsg.mn_ReplyPort = IoSink;
  789.     han->ff_RdMsg.mn_Node.ln_Name = (char *)han;
  790.     han->ff_WrMsg.mn_ReplyPort = IoSink;
  791.     han->ff_WrMsg.mn_Node.ln_Name = (char *)han;
  792.     NewList((MaxList *)&han->ff_RdWait);
  793.     NewList((MaxList *)&han->ff_WrWait);
  794.  
  795.     if (han_flags & FHF_COOKED) {
  796.     /*  allocation need not be public, fifo-handler use only */
  797.     if (NULL == (han->ff_CookBuf = AllocMem(CB_SIZE, MEMF_CLEAR)))
  798.         goto fail;
  799.     /*  lookahead for efficiency */
  800.     RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  801.     han->ff_Flags |= FHF_RPEND;
  802.     }
  803.     return han;
  804.  
  805.     fail:
  806.     CloseHandle(han);
  807.     return NULL;
  808. }
  809.  
  810. void
  811. CloseHandle(han)
  812. FHan *han;
  813. {
  814.     /*  zero fields to protect against buggy programs */
  815.     Remove(&han->ff_Node);
  816.     if (han->ff_SRead) {
  817.     if (--han->ff_SRead->sr_Refs == 0) {
  818.         if (han->ff_FifoR) {
  819.         CloseFifo(han->ff_FifoR, 0);
  820.         /* han->ff_FifoR = NULL; */
  821.         }
  822.         FreeMem(han->ff_SRead, sizeof(SharRead));
  823.     }
  824.     han->ff_SRead = NULL;
  825.     }
  826.     if (han->ff_FifoW) {
  827.     CloseFifo(han->ff_FifoW, (han->ff_Flags & FHF_CLOSEEOF) ? FIFOF_EOF : 0);
  828.     han->ff_FifoW = NULL;
  829.     }
  830.     if (han->ff_Port) {
  831.     FreeMem(han->ff_Port, sizeof(MsgPort) + sizeof(Interrupt));
  832.     han->ff_Port = NULL;
  833.     }
  834.     if (han->ff_CookBuf) {
  835.     FreeMem(han->ff_CookBuf, CB_SIZE);
  836.     han->ff_CookBuf = NULL;
  837.     }
  838.     FreeMem(han, sizeof(FHan) + strlen(han->ff_Node.ln_Name) + 1);
  839. }
  840.  
  841.  
  842. /*
  843.  *  handle cooked data by actually reading it from the fifo, echoing it
  844.  *  to the return channel (if it exists), and processing it.  If a <CR>
  845.  *  is processed, handle any
  846.  */
  847.  
  848. void
  849. HandleRequestMsg(Message *msg)
  850. {
  851.     FHan *han = (FHan *)msg->mn_Node.ln_Name;
  852.  
  853.     if (msg == &han->ff_WrMsg) {
  854.     han->ff_Flags &= ~FHF_WAVAIL;
  855.     while ((msg = (Message *)RemHead((MaxList *)&han->ff_WrWait))) /*  retry operation */
  856.         PutMsg(PktPort, msg);
  857.  
  858.     /*
  859.      *  if we were blocked trying to echo, then read data pending,
  860.      *  make sure read-request is queued and will be retried.
  861.      */
  862.  
  863.     if (han->ff_Flags & FHF_COOKECHOBLK) {
  864.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  865.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  866.         han->ff_Flags |= FHF_RPEND;
  867.         }
  868.         han->ff_Flags &= ~FHF_COOKECHOBLK;
  869.     }
  870.     } else if (msg == &han->ff_RdMsg) {
  871.     han->ff_Flags &= ~FHF_RPEND;
  872.     if (han->ff_Flags & FHF_COOKED) {
  873.         long n;
  874.         long i;
  875.         short rwakeup = 0;
  876.         char *ptr;
  877.  
  878.         n = ReadFifo(han->ff_FifoR, &ptr, 0);
  879.  
  880.         if (n < 0) {
  881.         han->ff_Flags |= FHF_REOF;
  882.         rwakeup = 1;
  883.         }
  884.  
  885.         for (i = 0; i < n; ++i) {
  886.         switch(ptr[i]) {
  887.         case 13:
  888.         case 10:
  889.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  890.             han->ff_Flags |= FHF_COOKBFUL;
  891.             n = --i;
  892.             break;
  893.             }
  894.             if (han->ff_FifoW) {
  895.             if (WriteFifo(han->ff_FifoW, "\r\n", 2) != 2) {
  896.                 han->ff_Flags |= FHF_COOKECHOBLK;
  897.                 n = --i;
  898.                 break;
  899.             }
  900.             }
  901.             /*  split buffer into \0 terminated strings */
  902.             han->ff_CookBuf[han->ff_CookIdx++] = 0;
  903.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  904.             han->ff_LRet = 1;
  905.             rwakeup = 1;
  906.             break;
  907.         case 8:
  908.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] != 0) {
  909.             if (han->ff_FifoW) {
  910.                 if (WriteFifo(han->ff_FifoW, "\010 \010", 3) != 3) {
  911.                 han->ff_Flags |= FHF_COOKECHOBLK;
  912.                 n = --i;
  913.                 break;
  914.                 }
  915.             }
  916.             han->ff_CookBuf[--han->ff_CookIdx] = 0;
  917.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] == 0)
  918.                 han->ff_LRet = 1;
  919.             }
  920.             break;
  921.         default:
  922.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  923.             han->ff_Flags |= FHF_COOKBFUL;
  924.             n = --i;
  925.             break;
  926.             }
  927.             if (han->ff_FifoW) {
  928.             if (WriteFifo(han->ff_FifoW, ptr + i, 1) != 1) {
  929.                 han->ff_Flags |= FHF_COOKECHOBLK;
  930.                 n = --i;
  931.                 break;
  932.             }
  933.             }
  934.             han->ff_CookBuf[han->ff_CookIdx++] = ptr[i];
  935.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  936.             han->ff_LRet = 0;
  937.             break;
  938.         }
  939.         }
  940.  
  941.         /*
  942.          *    if output was held due to cooked input pending, and the
  943.          *    case is no longer true, then restart output
  944.          */
  945.  
  946.         if ((han->ff_Flags & FHF_WIHOLD) && (han->ff_LRet || han->ff_CookIdx == 0)) {
  947.         han->ff_Flags &= ~FHF_WIHOLD;
  948.         while ((msg = (Message *)RemHead((MaxList *)&han->ff_WrWait)))
  949.             PutMsg(PktPort, msg);
  950.         }
  951.  
  952.         if (i > 0) {
  953.         if (ReadFifo(han->ff_FifoR, &ptr, i) < 0) {
  954.             han->ff_Flags |= FHF_REOF;
  955.             rwakeup = 1;
  956.         }
  957.         }
  958.         if (n >= 0 && !(han->ff_Flags & (FHF_COOKECHOBLK|FHF_COOKBFUL|FHF_REOF))) {
  959.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  960.         han->ff_Flags |= FHF_RPEND;
  961.         }
  962.         if (!rwakeup)
  963.         return;
  964.     }
  965.     while ((msg = (Message *)RemHead((MaxList *)&han->ff_RdWait))) /*  retry operation */
  966.         PutMsg(PktPort, msg);
  967.     }
  968. }
  969.  
  970. void
  971. WaitMsg(Message *msg)
  972. {
  973.     while (msg->mn_Node.ln_Type == NT_MESSAGE)
  974.     Wait(1 << msg->mn_ReplyPort->mp_SigBit);
  975.     Forbid();
  976.     Remove(&msg->mn_Node);
  977.     Permit();
  978. }
  979.  
  980. void
  981. SigHandles(char *name, unsigned long sigs)
  982. {
  983.     FHan *han;
  984.  
  985.     for (han = (FHan *)HanList.mlh_Head; han->ff_Node.ln_Succ; han = (FHan *)han->ff_Node.ln_Succ) {
  986.     if (strcmp(han->ff_Node.ln_Name, name) == 0) {
  987.         MsgPort *mp = han->ff_SigPort;
  988.         D(ebug("Maybe signal port %08lx %s\n", mp, name));
  989.         if ((mp->mp_Flags & PF_ACTION) == PA_SIGNAL)
  990.         Signal(mp->mp_SigTask, sigs);
  991.     }
  992.     }
  993. }
  994.  
  995.  
  996. /*
  997.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  998.  *  can see by this and how the PACKET structure is extracted in the
  999.  *  GetMsg() of the main routine.
  1000.  */
  1001.  
  1002. void
  1003. returnpacket(DosPacket *packet)
  1004. {
  1005.     MsgPort *replyPort         = packet->dp_Port;
  1006.     Message *mess         = packet->dp_Link;
  1007.     packet->dp_Port         = PktPort;    /*  not possibly special port? */
  1008.     mess->mn_Node.ln_Name    = (char *)packet;
  1009.     PutMsg(replyPort, mess);
  1010. }
  1011.  
  1012. void
  1013. Initialize(void)
  1014. {
  1015. #ifndef CLI_START
  1016.     Process *proc = FindTask(NULL);
  1017.     DosPacket *packet;
  1018. #endif
  1019.  
  1020.     /*
  1021.      *    Initialize port
  1022.      */
  1023.     {
  1024.     IoSink = CreatePort("FIFO-PORT", -10);
  1025.     FreeSignal(IoSink->mp_SigBit);
  1026.     IoSink->mp_SigBit = SIGBREAKB_CTRL_F; /*  why? (jch) */
  1027.     }
  1028.     PktPort = CreatePort(NULL, 0);
  1029.     TimerPort = CreatePort(NULL, 0);
  1030.     TimerIO = (WaitTreq *) CreateExtIO(TimerPort, sizeof(WaitTreq));
  1031.     OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0);
  1032.     TimerIO->wt_timereq.tr_node.io_Command = TR_ADDREQUEST;
  1033.     PortsMask = (1 << PktPort->mp_SigBit) | (1 << TimerPort->mp_SigBit);
  1034.  
  1035. #ifdef CLI_START
  1036.  
  1037.     /*
  1038.      *    create DOS node
  1039.      */
  1040.  
  1041.     MkDevice("FIFO");
  1042.  
  1043.     FifoBase = OpenLibrary(FIFONAME, 0);
  1044.  
  1045. #else
  1046.  
  1047.     /*
  1048.      *    Handle initial message.     We pull the message off the port before
  1049.      *    calling OpenLibrary() so if OpenLibrary() makes a DOS call it
  1050.      *    doesn't crash the machine (due to an unexpected packet).  This
  1051.      *    will happen if the library needs to be loaded.    There is no other
  1052.      *    safe time to do this.
  1053.      */
  1054.  
  1055.     {
  1056.     Message *msg;
  1057.  
  1058.     WaitPort(&proc->pr_MsgPort);
  1059.     msg = GetMsg(&proc->pr_MsgPort);
  1060.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1061.     }
  1062.  
  1063.     /*
  1064.      *    Fifo Library
  1065.      */
  1066.  
  1067.     FifoBase = OpenLibrary(FIFONAME, 0);
  1068.  
  1069.     {
  1070.     DeviceNode *dn;
  1071.     DevNode = dn = BTOC(packet->dp_Arg3);
  1072.  
  1073.     dn->dn_Task = PktPort;
  1074.     packet->dp_Res1 = (FifoBase) ? DOS_TRUE : DOS_FALSE;
  1075.     packet->dp_Res2 = 0;
  1076.     returnpacket(packet);
  1077.     }
  1078.  
  1079. #endif
  1080. }
  1081.  
  1082.  
  1083. int
  1084. myexit(int code)
  1085. {
  1086. #ifdef CLI_START
  1087.     DelDevice();
  1088. #else
  1089.  
  1090.     /*
  1091.      *    Device Node
  1092.      */
  1093.  
  1094.     {
  1095.     DeviceNode *dn = DevNode;
  1096.  
  1097.     dn->dn_Task = NULL;
  1098.     dn->dn_SegList = NULL;
  1099.     }
  1100. #endif
  1101.  
  1102.     /*
  1103.      *    delete ports
  1104.      */
  1105.  
  1106.     CloseDevice((struct IORequest *) TimerIO);
  1107.     DeleteExtIO((struct IORequest *) TimerIO);
  1108.     DeletePort(TimerPort);
  1109.  
  1110.     if (PktPort)
  1111.     DeletePort(PktPort);
  1112.  
  1113.     if (IoSink) {
  1114.     IoSink->mp_SigBit = AllocSignal(-1);
  1115.     DeletePort(IoSink);
  1116.     }
  1117.  
  1118. #ifdef DEBUG
  1119.     if (DBFifo) {
  1120.     CloseFifo(DBFifo, FIFOF_EOF);
  1121.     DBFifo = NULL;
  1122.     }
  1123. #endif
  1124.     if (FifoBase) {
  1125.     CloseLibrary(FifoBase);
  1126.     FifoBase = NULL;
  1127.     }
  1128.     _exit(code);        /*  some startups always return 0 from main */
  1129.     return code;
  1130. }
  1131.  
  1132.  
  1133. MsgPort *
  1134. SpecPort(FHan *han)
  1135. {
  1136.     MsgPort *port = AllocMem(sizeof(MsgPort) + sizeof(Interrupt), MEMF_CLEAR | MEMF_PUBLIC);
  1137.     Interrupt *xint = (Interrupt *)(port + 1);
  1138.     extern void AIntCode();
  1139.     if (NULL == port) return NULL;
  1140.  
  1141.     NewList(&port->mp_MsgList);
  1142.     port->mp_Node.ln_Name = (char *)han; /*  ln_name holds local data */
  1143.     port->mp_Node.ln_Type = NT_MSGPORT;
  1144.     port->mp_Flags = PA_SOFTINT;
  1145.     port->mp_SigTask = (void *)xint;
  1146.     xint->is_Node.ln_Type = NT_INTERRUPT;
  1147.     xint->is_Node.ln_Pri  = -32;
  1148.     xint->is_Data = (APTR)port;
  1149.     xint->is_Code = AIntCode;
  1150.     return(port);
  1151. }
  1152.  
  1153. #if !defined(__GNUC__)
  1154. __geta4 __stkargs
  1155. #endif
  1156. void
  1157. IntCode(port)
  1158. MsgPort *port;
  1159. {
  1160.     Message *msg;
  1161.     DosPacket *packet;
  1162.     FileHandle *fh;
  1163.  
  1164.     while ((msg = GetMsg(port))) {
  1165.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  1166.     D(ebug("Port %08lx, type %ld\n", packet->dp_Type));
  1167.  
  1168.     switch(packet->dp_Type) {
  1169.     case ACTION_FINDUPDATE:
  1170.     case ACTION_FINDINPUT:
  1171.     case ACTION_FINDOUTPUT:
  1172.         fh = BTOC(packet->dp_Arg1);
  1173.         fh->fh_Port = port;    /*  temporary storage */
  1174.         break;
  1175.     case ACTION_SCREEN_MODE:
  1176.         packet->dp_Type = FACTION_SCREEN_MODE;
  1177.         packet->dp_Res1 = (LONG)port; /*  we are not allowed to change dp->Arg2 */
  1178.         break;
  1179.     case ACTION_WAIT_CHAR:
  1180.         packet->dp_Type = FACTION_WAIT_CHAR;
  1181.         packet->dp_Res1 = (LONG)port; /*  we are not allowed to change dp->Arg2 */
  1182.         break;
  1183.     }
  1184.     PutMsg(PktPort, msg);
  1185.     }
  1186. }
  1187.  
  1188. #ifdef DEBUG
  1189.  
  1190. void
  1191. xprintf(char *ctl, ...)
  1192. {
  1193.     va_list va;
  1194.     static char buf[256];
  1195.     int n;
  1196.  
  1197.     if (DBFifo) {
  1198.     va_start(va, ctl);
  1199.     n = vsprintf(buf, ctl, va);
  1200.     if (n > 0)
  1201.         WriteFifo(DBFifo, buf, n);
  1202.     va_end(va);
  1203.     }
  1204. }
  1205.  
  1206. #endif
  1207.  
  1208. #ifdef CLI_START
  1209.  
  1210. /*
  1211.  *  DEVICE CREATION AND DELETION
  1212.  */
  1213.  
  1214. __inline__ static
  1215. void *
  1216. DosAllocMem(bytes)
  1217. long bytes;
  1218. {
  1219.     long *ptr;
  1220.  
  1221.     bytes += 4;
  1222.  
  1223.     if ((ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR))) {
  1224.     *ptr++ = bytes;
  1225.     return((void *)ptr);
  1226.     }
  1227.     Alert(AG_NoMemory|AT_DeadEnd);
  1228.     return NULL;        /*  NOTREACHED */
  1229. }
  1230.  
  1231. __inline__ static
  1232. void
  1233. DosFree(void *vptr)
  1234. {
  1235.     long *ptr = vptr;
  1236.     --ptr;
  1237.     FreeMem(ptr, *ptr);
  1238. }
  1239.  
  1240. DosList *Dl;
  1241.  
  1242. void
  1243. MkDevice(char *devName)
  1244. {
  1245.     DosList *dl;
  1246.     RootNode *root;
  1247.     DosInfo *info;
  1248.  
  1249.     Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
  1250.     strcpy((char *)(dl+1) + 1, devName);
  1251.     *(char *)(dl + 1) = strlen(devName);
  1252.     dl->dol_Type = DLT_DEVICE;
  1253.     dl->dol_Task = PktPort;
  1254.     dl->dol_Name = MKBADDR((char *)(dl+1));
  1255.  
  1256.     Forbid();
  1257.     root  = (struct RootNode *)DOSBase->dl_Root;
  1258.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1259.     dl->dol_Next = info->di_DevInfo;
  1260.     info->di_DevInfo = MKBADDR(dl);
  1261.     Permit();
  1262. }
  1263.  
  1264. void
  1265. DelDevice(void)
  1266. {
  1267.     DosList *dl;
  1268.     DosInfo *info;
  1269.     RootNode *root;
  1270.     DosList *dls;
  1271.     BPTR    *bpp;
  1272.  
  1273.     if ((dl = Dl)) {
  1274.     Forbid();
  1275.     root  = (struct RootNode *)DOSBase->dl_Root;
  1276.     info  = (struct DosInfo     *)BADDR(root->rn_Info);
  1277.  
  1278.     for (bpp = &info->di_DevInfo; (dls = BADDR(*bpp)); bpp = &dls->dol_Next) {
  1279.         if (dls == dl)
  1280.         break;
  1281.     }
  1282.     if (dls == dl) {
  1283.         *bpp = dls->dol_Next;
  1284.     } else {
  1285.         Alert(0x07AAAAAA|AT_Recovery);
  1286.     }
  1287.     Permit();
  1288.     DosFree(dl);
  1289.     Dl = NULL;
  1290.     }
  1291. }
  1292.  
  1293. #endif
  1294.  
  1295. WaitTreq *
  1296. AllocTimerequest(unsigned long timeout)
  1297. {
  1298.   struct WaitTreq *tr = (struct WaitTreq *)AllocMem(sizeof(WaitTreq), MEMF_PUBLIC);
  1299.  
  1300.   if (NULL != tr) {
  1301.       memmove(tr, TimerIO, sizeof(tr->wt_timereq));
  1302.       tr->wt_timereq.tr_time.tv_secs = 0;
  1303.       while (timeout >= 1000000) {
  1304.       tr->wt_timereq.tr_time.tv_secs++;
  1305.       timeout -= 1000000;
  1306.       }
  1307.       tr->wt_timereq.tr_time.tv_micro = timeout;
  1308.   }
  1309.   return tr;
  1310. }
  1311.